package com.onpositive.units;

import java.util.Arrays;

import org.w3c.dom.Element;

import com.onpositive.knowledge.model.values.IHasValue;
import com.onpositive.semantic.model.api.meta.BaseMeta;
import com.onpositive.semantic.model.api.meta.IWritableMeta;


public class ValueCluster<T extends ParsedValue> extends ParsedValueSequenceV2
{
	//T is a targetValue Class ;
	private static final long serialVersionUID = -3584616792325812245L;
	public static final String ID = "cluster" ;

	private final T targetValue ;
	private final Class<T> targetClass ;	
	public ValueCluster(
			ParsedValue[] valuesArray,
			Class<T> clazz,
			int targetInd,
			String comment,
			String[] prefixAndPostfix )
	{		
		super( valuesArray, comment, prefixAndPostfix ) ;		
		
		this.targetClass = clazz ;

		ParsedValue val = valuesArray[targetInd] ;
		
		if (targetClass.isInstance(val)){
			targetValue = targetClass.cast(val) ;
		}		
		else 
		{
			targetValue=null;//TODO FIX ME
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public ValueCluster( ParsedValue pv, String comment )
	{
		super( pv, comment ) ;
		ValueCluster other = (ValueCluster) pv ;
		this.targetClass = other.targetClass ;
		int targetInd = computeTargetInd(other);
		this.targetValue = (T) this.valuesArray[targetInd] ;
	}
	
	@SuppressWarnings("unchecked")
	private ValueCluster( ValueCluster<?> other, ParsedValue[] valArr, String comment )
	{
		super( other, valArr, comment ) ;
		this.targetClass = (Class<T>) other.targetClass ;
		int ind = computeTargetInd(other) ;
		this.targetValue = (T) valuesArray[ind] ;
	}

	static public int computeTargetInd(ValueCluster other) {
		int targetInd = 0 ;
		for( ; other.valuesArray[targetInd] != other.targetValue ; targetInd++ ) ;
		return targetInd;
	}
	
	@SuppressWarnings("unchecked")
	public ValueCluster( Element element ) {
		super(element);		
		
		int targetInd = Integer.parseInt( element.getAttribute("target-val") );		
		targetValue = (T) valuesArray[targetInd] ;		
		targetClass = (Class<T>) targetValue.getClass() ;
	}
	
	@Override
	public void writeValue(Element element) {
		
		super.writeValue(element) ;
		
		int targetInd = computeTargetInd(this) ;		
		element.setAttribute("target-val", ""+targetInd ) ;		
	}

	@Override
	public Object value() {
		// TODO is this right?
		return getValuesArray() ;
	}

	@Override
	public void setValue(Object obj) {}

	@Override
	public Object describer() {
		// TODO what's the sense?
		return null;
	}

	@Override
	public String getId() {
		return ID ;
	}

	public T getTargetValue() {
		return targetValue;
	}

	@Override
	public String getValueAsString()
	{
		StringBuilder bld = new StringBuilder() ;
		for( ParsedValue pv : valuesArray )
		{
			String str = pv.getValueAsString().trim() ;
			bld.append(str) ;
			bld.append(" " ) ;
		}		
		final String result = bld.substring( 0, bld.length()-1 );
		return result ;
	}
	

	public Class<T> getTargetClass() {
		return targetClass;
	}

	@Override
	protected  IWritableMeta createMeta() {
		
		IWritableMeta meta = super.createMeta() ;
		if (targetValue!=null){
		meta.putMeta( META_KEY_VALUE_TYPE, targetValue.getMeta().getSingleValue(
				META_KEY_VALUE_TYPE,
				String.class,
				null) ) ;
		}
		meta.putMeta( META_KEY_ID, getId() ) ;		
		return meta ;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((targetClass == null) ? 0 : targetClass.hashCode());
		result = prime * result
				+ ((targetValue == null) ? 0 : targetValue.hashCode());
		result = prime * result + Arrays.hashCode(valuesArray);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ValueCluster other = (ValueCluster) obj;
		if (targetClass == null) {
			if (other.targetClass != null)
				return false;
		} else if (!targetClass.equals(other.targetClass))
			return false;
		if (targetValue == null) {
			if (other.targetValue != null)
				return false;
		} else if (!targetValue.equals(other.targetValue))
			return false;
		if (!Arrays.equals(valuesArray, other.valuesArray))
			return false;
		return true;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public IHasValue clone(Object value, String comment) {
		if( !(value instanceof ParsedValue[]) )
			return null;
		
		if( comment == null )
			comment = this.getComment() ;
		ParsedValue[] valArr = (ParsedValue[]) value ;
		return new ValueCluster( this, valArr, comment ) ;		
	}
	


}
